home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / CURSES.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-18  |  23.9 KB  |  1,116 lines

  1. #ifdef UNIX
  2. /*
  3.  * Intelligent session manager using curses.  Options include ANSI X3.64
  4.  * emulation with both VTx00 and PC graphics.
  5.  *
  6.  * Brandon S. Allbery KF8NH
  7.  * No copyright, copyleft, copysideways, copytwisted, ....
  8.  */
  9.  
  10. #include <sys/types.h>
  11. #include <errno.h>
  12. #include <sys/param.h>
  13. #include "system.h"
  14. /*lint -save -e659 */
  15. #ifdef HAVE_NCURSES_H
  16. #include <ncurses.h>
  17. #else
  18. #include <curses.h>
  19. #endif
  20. /*lint -restore */
  21. #ifndef MSDOS
  22. #include <term.h>
  23. #endif
  24. #undef FALSE
  25. #undef TRUE
  26.  
  27. #ifndef _lint
  28. static char rcsid[] OPTIONAL = "$Id: curses.c,v 1.20 1997/08/19 01:19:22 root Exp root $";
  29. #endif
  30.  
  31. # ifndef    wbkgdset
  32. #  define wbkgdset(w,attr) ((w)->_bkgd = (attr))
  33. # endif
  34. # ifndef getattrs
  35. #  define getattrs(w) ((w)->_attrs)
  36. # endif
  37.  
  38.  
  39. #ifdef memcpy
  40. #undef memcpy
  41. #endif
  42.  
  43. #include "global.h"
  44. #include "hardware.h"
  45. #include "proc.h"
  46. #undef tputs
  47. #include "tty.h"
  48. /*lint -e123 */
  49. #include "sessmgr.h"
  50.  
  51. /* This nonsense WILL go away... */
  52. #ifdef NO_CURSES_TMARG
  53. # define _tmarg _regtop
  54. # define _bmarg _regbottom
  55. #endif
  56.  
  57. #ifdef SM_CURSES
  58.  
  59. #ifdef SCREENSAVER
  60. extern void sskick (void);
  61. #endif
  62.  
  63. extern struct sessmgr_sw curses_sessmgr; /* forward declaration */
  64.  
  65. static int Suspense, initted;
  66. #ifdef RAW_SESSMGR
  67. static TERMINAL *my_term;
  68. #endif
  69. static void *curscreen;
  70. extern int Numrows, Numcols;
  71. extern int Keyboard;
  72. extern int SYSback, SYSfore;
  73.  
  74.  
  75. /* colors - this is a mess */
  76. static int *color_pair_map;
  77.  
  78.  
  79. struct keytrie
  80. {
  81.     enum {KT_DEF, KT_TRIE, KT_TVAL, KT_VAL} kt_type; /* type of entry */
  82.     int kt_tval;        /* if a TVAL, the timed-out value */
  83.     union
  84.     {
  85.     struct keytrie *ktu_trie; /* sub-trie */
  86. #define kt_trie kt_u.ktu_trie
  87.     int ktu_val;        /* value */
  88. #define kt_val kt_u.ktu_val
  89.     } kt_u;
  90. };
  91.  
  92.  
  93. struct curses_data
  94. {
  95.     WINDOW *win;
  96.     struct
  97.     {
  98.     int x, y, tmarg, bmarg, valid;
  99.     chtype attr, bkgrnd;
  100.     } save;
  101.     char parm[8];
  102.     char nparm;
  103.     char bg;            /* current background */
  104.     char fg;            /* current foreground */
  105.     char flags;
  106. #define C_ESC        0x01
  107. #define C_CSI        0x02
  108. #define C_INS        0x04
  109. #define C_TTY        0x08
  110. #define C_BOLD        0x10
  111. };
  112.  
  113.  
  114. static struct keytrie *keys;
  115.  
  116. /* mapping of IBM line-drawing characters to curses line drawing */
  117. /* this is evil: it doesn't use e.g. ACS_HLINE because that's an array ref */
  118. static chtype ibm_map[128] =
  119. {
  120.      0,   0,   0,   0,   0,   0,   0,   0,
  121.      0,   0,   0,   0,   0,   0,   0,   0,
  122.      0,   0,   0,   0,   0,   0,   0,   0,
  123.      0,   0,   0,   0,   0,   0,   0,   0,
  124.      0,   0,   0,   0,   0,   0,   0,   0,
  125.      0,   0,   0,   0,   0,   0,   0,   0,
  126.     'a', 'a', 'a', 'x', 'u', 'u', 'u', 'k',
  127.     'k', 'u', 'x', 'k', 'j', 'j', 'j', 'k',
  128.     'm', 'v', 'w', 'u', 'q', 'n', 'u', 'u',
  129.     'j', 'l', 'v', 'w', 'u', 'q', 'n', 'v',
  130.     'v', 'w', 'w', 'm', 'm', 'l', 'l', 'n',
  131.     'n', 'j', 'l',  0,   0,   0,   0,   0,
  132.      0,   0,   0,   0,   0,   0,   0,   0,
  133.      0,   0,   0,   0,   0,   0,   0,   0,
  134.      0,   0,   0,   0,   0,   0,   0,   0,
  135.      0,   0,   0,   0,   0,   0,   0,   0,
  136. };
  137.  
  138.  
  139.  
  140. /*lint -save -e550 */
  141. static int
  142. Getmaxy (WINDOW *w)
  143. {
  144. int y, x;
  145.  
  146.     getmaxyx(w, y, x);
  147.     return y;
  148. }
  149.  
  150. static int
  151. Getmaxx (WINDOW *w)
  152. {
  153. int y, x;
  154.  
  155.     getmaxyx(w, y, x);
  156.     return x;
  157. }
  158. /*lint -restore */
  159.  
  160.  
  161.  
  162. static struct keytrie *
  163. key_init (void)
  164. {
  165. struct keytrie *k;
  166. int i;
  167.  
  168.     k = mallocw(256 * sizeof *keys);
  169.     for (i = 256; i--; )    {
  170.         k[i].kt_type = KT_DEF;
  171.         k[i].kt_val = i;
  172.     }
  173.     return k;
  174. }
  175.  
  176.  
  177.  
  178. static void
  179. key_add (const char *str, int val)
  180. {
  181. struct keytrie *t;
  182. int c;
  183.  
  184.     /*
  185.      * Follow the trie until we get to the right subtrie for the string, then
  186.      * add the value.  If we hit a KT_DEF, expand the trie.  If we hit a KT_VAL
  187.      * change it to a KT_TVAL, which times out as a KT_VAL but continues as a
  188.      * KT_TRIE.  If given a value for a KT_TRIE, change it to a KT_TVAL.
  189.      */
  190.     if (!str || !*str)
  191.         return;            /* no key to define */
  192.     t = keys;
  193.     while (str[1])    {
  194.         c = uchar(*str++);
  195.         if (t[c].kt_type != KT_TRIE)    {
  196.             if (t[c].kt_type == KT_DEF)
  197.                 t[c].kt_type = KT_TRIE;
  198.             else        {
  199.                 t[c].kt_type = KT_TVAL;
  200.                 t[c].kt_tval = t[c].kt_val;
  201.             }
  202.             t[c].kt_trie = key_init();
  203.         }
  204.         t = t[c].kt_trie;
  205.     }
  206.     c = uchar(*str);
  207.     if (t[c].kt_type == KT_TRIE)    {
  208.         t[c].kt_type = KT_TVAL;
  209.         t[c].kt_tval = val;
  210.     } else if (t[c].kt_type == KT_DEF)    {
  211.         t[c].kt_type = KT_VAL;
  212.         t[c].kt_val = val;
  213.     }
  214. }
  215.  
  216. /*lint -restore */
  217.  
  218.  
  219.  
  220. static int
  221. map_colors(int bg, int fg)
  222. {
  223. int cp, cmask;
  224.  
  225.     if (!color_pair_map)
  226.         return 0;
  227. #ifdef DEBUGCOLOR
  228.     fprintf (stderr, "map_colors %d %d", bg, fg);
  229. #endif
  230.     cmask = (int) ((unsigned int) bg << 4) | fg;
  231.     for (cp = 0; cp < COLOR_PAIRS; cp++)    {
  232.         if (color_pair_map[cp] == -1 || color_pair_map[cp] == cmask)
  233.             break;
  234.     }
  235.  
  236.     if (cp == COLOR_PAIRS)    {
  237. #ifdef DEBUGCOLOR
  238.         fprintf(stderr, " - out of pairs!\n");
  239. #endif
  240.         return 0;
  241.     }
  242.  
  243.     if (color_pair_map[cp] == -1)    {
  244.         if (init_pair((short)(cp + 1), (short) fg, (short) bg) == ERR)    {
  245. #ifdef DEBUGCOLOR
  246.             fprintf(stderr, "can't create pair %d\n", cp);
  247. #endif
  248.             cp = 0;
  249.         } else    {
  250. #ifdef DEBUGCOLOR
  251.             fprintf(stderr, " - new pair %d\n", cp);
  252. #endif
  253.             color_pair_map[cp] = cmask;
  254.         }
  255.     }
  256. #ifdef DEBUGCOLOR
  257.     else
  258.         fprintf(stderr, " is pair %d\n", cp);
  259. #endif
  260.     return ((int) COLOR_PAIR((unsigned int)(cp + 1)));
  261. }
  262.  
  263.  
  264.  
  265. static int
  266. curses_init(const struct sessmgr_sw *sm OPTIONAL)
  267. {
  268.     if (!isatty(0))
  269.         return 0;
  270.     if (initted)    {
  271. #ifdef RAW_SESSMGR
  272.         set_curterm(my_term);
  273. #endif
  274.         (void) refresh();        /* bring curses back to life */
  275.     } else    {
  276.         (void) initscr();            /* be nice to trap errors... */
  277.         /*
  278.          * I assume the curses manpage tells the truth when it claims that
  279.          * colors are initialized to RGB defaults.  If not, I may need to set
  280.          * up the colors in question...
  281.          */
  282.         if (has_colors() && start_color() != ERR && COLORS >= 8)    {
  283.             color_pair_map = mallocw((unsigned int)COLOR_PAIRS * sizeof(int));
  284.             memset(color_pair_map, -1, ((unsigned int) COLOR_PAIRS) * sizeof(int));
  285.             (void) map_colors(SYSback, SYSfore); /* default color pair */
  286.         }
  287. #ifdef RAW_SESSMGR
  288.         my_term = cur_term;
  289. #endif
  290.         (void) noecho();
  291.         (void) nonl();
  292.         (void) raw();
  293.         keys = key_init();
  294.         key_add(key_down, DNARROW);
  295.         key_add(key_f1, -3);
  296.         key_add(key_f2, -4);
  297.         key_add(key_f3, -5);
  298.         key_add(key_f4, -6);
  299.         key_add(key_f5, -7);
  300.         key_add(key_f6, -8);
  301.         key_add(key_f7, -9);
  302.         key_add(key_f8, -10);
  303.         key_add(key_f9, -11);
  304.         key_add(key_ic, -105);
  305.         key_add(key_dc, -106);
  306.         key_add(key_home, -107);
  307.         key_add(key_end, -108);
  308.         key_add(key_ppage, -109);
  309.         key_add(key_npage, -110);
  310.         key_add(key_f10, -2);
  311.         key_add(key_left, LTARROW);
  312.         key_add(key_right, RTARROW);
  313.         key_add(key_up, UPARROW);
  314.         key_add("\177", '\b');    /* so DEL behaves as BS */
  315.         initted = 1;
  316.     }
  317.     Suspense = 0;
  318.     Numrows = LINES;
  319.     Numcols = COLS;
  320.     return 1;
  321. }
  322.  
  323.  
  324.  
  325. static void
  326. curses_end (const struct sessmgr_sw *sm OPTIONAL)
  327. {
  328.     if (!Suspense)
  329.         (void) endwin();
  330. }
  331.  
  332.  
  333.  
  334. static void
  335. curses_suspend (const struct sessmgr_sw *sm OPTIONAL)
  336. {
  337.     if (!Suspense++)    {
  338.         /* note that we use stdscr for this, since it's otherwise unoccupied */
  339.         (void) clear();
  340.         (void) refresh();
  341.         (void) endwin();
  342.     }
  343. }
  344.  
  345.  
  346.  
  347. static void
  348. curses_resume(const struct sessmgr_sw *sm OPTIONAL)
  349. {
  350.     if (!--Suspense)    {
  351. #ifdef RAW_SESSMGR
  352.         set_curterm(my_term);
  353. #endif
  354.          (void) clearok(((struct curses_data *) curscreen)->win, TRUE);
  355.         (void) wrefresh(((struct curses_data *) curscreen)->win);
  356.         Numrows = LINES;
  357.         Numcols = COLS;
  358.     }
  359. }
  360.  
  361.  
  362.  
  363. /*
  364.  * Options supported:
  365.  *
  366.  * tty, ansi
  367.  *    Select old glass-tty emulation or new ANSI X3.64 emulation
  368.  *
  369.  * bold
  370.  *    Specify style of highlight used
  371.  */
  372.  
  373. static char *
  374. curses_opts(const struct sessmgr_sw *sm OPTIONAL, void *sp, const char *opts)
  375. {
  376. struct curses_data *cp;
  377. static char buf[1024];
  378. char const *ep;
  379. char const *xp;
  380. size_t l;
  381.  
  382.     cp = (struct curses_data *) sp;
  383.     if (!opts)    {
  384.         /* return printable version of options */
  385.         buf[0] = '\0';
  386.         if (cp->flags & C_TTY)
  387.             strcpy(buf, "tty");
  388.         if ((cp->flags & (C_TTY|C_BOLD)) == (C_TTY|C_BOLD))
  389.             strcat(buf, ",");
  390.         if (cp->flags & C_BOLD)
  391.             strcat(buf, "bold");
  392.         return buf;
  393.     }
  394.  
  395.     /* parse and set options */
  396.     xp = opts;
  397.     while (*xp)    {
  398.         while (isspace(*xp) || *xp == ',')
  399.             xp++;
  400.         if (!*xp)
  401.             break;
  402.         l = 0;
  403.         for (ep = xp; *ep && *ep != ',' && !isspace(*ep); ep++)
  404.             l++;
  405.         memcpy(buf, xp, l);
  406.         buf[l] = '\0';
  407.         if (strcasecmp(buf, "tty") == 0)
  408.             cp->flags |= C_TTY;
  409.         else if (strcasecmp(buf, "ansi") == 0)
  410.             cp->flags &= ~C_TTY;
  411.         else if (strcasecmp(buf, "notty") == 0)
  412.             cp->flags &= ~C_TTY;
  413.         else if (strcasecmp(buf, "noansi") == 0)
  414.             cp->flags |= C_TTY;
  415.         else if (strcasecmp(buf, "bold") == 0)
  416.             cp->flags |= C_BOLD;
  417.         else if (strcasecmp(buf, "nobold") == 0)
  418.             cp->flags &= ~C_BOLD;
  419.         else
  420.             tprintf("curses: unknown option \"%s\"\n", buf);
  421.         xp = ep;
  422.     }
  423.     
  424.     return 0;
  425. }
  426.  
  427.  
  428.  
  429. static int
  430. curses_swap (const struct sessmgr_sw *sm OPTIONAL, void *old OPTIONAL, void *new)
  431. {
  432.     if (new)    {
  433.         (void) clearok(((struct curses_data *) new)->win, TRUE);
  434.         (void) touchwin(((struct curses_data *) new)->win);
  435.         curscreen = new;
  436.     }
  437.     return 1;            /* can always run concurrent output */
  438. }
  439.  
  440.  
  441.  
  442. static void
  443. wiach (WINDOW *win, chtype ch, int insert)
  444. {
  445.     if (insert)
  446.         (void) winsch(win, (chtype) ch);
  447.     else
  448.         (void) waddch(win, (chtype) ch);
  449. }
  450.  
  451.  
  452.  
  453. static void
  454. curses_flush (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  455. {
  456.     if (!Suspense && curscreen == dp)
  457.         (void) wrefresh(((struct curses_data *) dp)->win);
  458. }
  459.  
  460.  
  461.  
  462. static void
  463. curses_putch (const struct sessmgr_sw *sm OPTIONAL, void *dp, int c)
  464. {
  465. register struct curses_data *sp;
  466. int x, y, ox, oy;
  467. chtype attrs;
  468.  
  469.     sp = dp;
  470.     if (c == 7)    {
  471.         write(1, "\7", 1);
  472.         return;
  473.     }
  474.  
  475. #ifdef SCREENSAVER
  476.     sskick();
  477. #endif
  478.  
  479.     if (c == '\r' || c == '\b')    {
  480.         (void) waddch(sp->win, (chtype) c);
  481.         return;
  482.     }
  483.     if (c == '\t')    {
  484.         wiach(sp->win, (chtype) c, sp->flags & C_INS);
  485.         return;
  486.     }
  487.     if (c == '\n')    {
  488.         /* waddch() does clrtoeol() implicitly.  This breaks us. */
  489.         getyx(sp->win, y, x);
  490.         if (++y > sp->win->_bmarg)    {
  491.             y--;
  492.             (void) scroll(sp->win);
  493. #if 1
  494.             if (Curproc->session->screen->flags & SMS_ACTIVE)
  495. #if 0
  496.                 (void) wrefresh (sp->win);
  497. #else
  498.                 curses_flush (sm, dp);
  499. #endif
  500. #endif
  501.         }
  502.         (void) wmove(sp->win, y, 0);
  503.         return;
  504.     }
  505.     if (sp->flags & C_TTY)    {
  506.         if (c >= 32 && c < 127)
  507.             wiach(sp->win, (chtype) c, sp->flags & C_INS);
  508.         return;
  509.     }
  510.     if (c == 24 || c == 26)    {
  511.         sp->flags &= ~(C_ESC|C_CSI);
  512.         return;
  513.     }
  514.     if (c == 27)    {
  515.         sp->flags |= C_ESC;
  516.         return;
  517.     }
  518.     if (c == '\016')    {
  519.         (void) wattron(sp->win, A_ALTCHARSET);
  520.         return;
  521.     }
  522.     if (c == '\017')    {
  523.         (void) wattroff(sp->win, A_ALTCHARSET);
  524.         return;
  525.     }
  526.     if (c < 32)
  527.         return;
  528.     if (!(sp->flags & (C_ESC|C_CSI)))    {
  529.         if (c > 127 && ibm_map[c - 128])
  530.             wiach(sp->win, ibm_map[c - 128] | A_ALTCHARSET, sp->flags & C_INS);
  531.         else if (c < 127)
  532.             wiach(sp->win, (chtype) c, sp->flags & C_INS);
  533.         return;
  534.     }
  535.     if (sp->flags & C_ESC)    {
  536.         /* we only handle '[' */
  537.         switch (c)    {
  538.             case '[':
  539.                 sp->flags &= ~C_ESC;
  540.                 sp->flags |= C_CSI;
  541.                 sp->nparm = 0;
  542.                 memset(sp->parm, 0, sizeof sp->parm);
  543.                 break;
  544.             case '7':
  545.                 getyx(sp->win, sp->save.y, sp->save.x);
  546.                 sp->save.attr = getattrs(sp->win);
  547.                 sp->save.tmarg = sp->win->_tmarg;
  548.                 sp->save.bmarg = sp->win->_bmarg;
  549.                 sp->save.bkgrnd = sp->win->_bkgd; /* should be a macro for this */
  550.                 sp->save.valid = 1;
  551.                 sp->flags &= ~(C_ESC|C_CSI);
  552.                 break;
  553.             case '8':
  554.                 if (sp->save.valid)        {
  555.                 (void) wmove(sp->win, sp->save.y, sp->save.x);
  556.                 wattrset(sp->win, sp->save.attr);
  557.                 wbkgdset(sp->win, sp->save.bkgrnd);
  558. #ifdef linux
  559.                 (void) werase(sp->win); /* wbkgdset() doesn't do anything */
  560. #endif
  561.                 (void) wsetscrreg(sp->win, sp->save.tmarg, sp->save.bmarg);
  562.                 sp->save.valid = 0;
  563.                 }
  564.                 sp->flags &= ~(C_ESC|C_CSI);
  565.                 break;
  566.             default:
  567.                 sp->flags &= ~(C_ESC|C_CSI);
  568.                 break;
  569.         }
  570.         return;
  571.     }
  572.  
  573.     /* handle CSI-sequences */
  574.     switch (c)    {
  575.         case '0':
  576.         case '1':
  577.         case '2':
  578.         case '3':
  579.         case '4':
  580.         case '5':
  581.         case '6':
  582.         case '7':
  583.         case '8':
  584.         case '9':
  585.         sp->parm[(int)sp->nparm] = (char) (sp->parm[(int)sp->nparm] * 10 + c - '0');
  586.         break;
  587.         case ';':
  588.         sp->parm[(int)(sp->nparm++)] = 0;
  589.         break;
  590.         case '?':
  591.         /* just ignore it for now */
  592.         break;
  593.         /* action character */
  594.         case 'H':
  595.         case 'f':
  596.         (void) wmove(sp->win, sp->parm[1] - 1, sp->parm[0] - 1);
  597.         sp->flags &= ~(C_ESC|C_CSI);
  598.         break;
  599.         case 'J':
  600.         switch (sp->parm[0])    {
  601.             case 0:
  602.                 attrs = getattrs(sp->win);
  603.                 wattrset(sp->win, A_NORMAL);
  604.                 (void) wclrtobot(sp->win);
  605.                 wattrset(sp->win, attrs);
  606.                 break;
  607.             case 1:
  608.                 getyx(sp->win, oy, ox);
  609.                 attrs = getattrs(sp->win);
  610.                 wattrset(sp->win, A_NORMAL);
  611.                 for (y = 0; y < oy; y++)        {
  612.                 (void) wmove(sp->win, y, 0);
  613.                 for (x = Getmaxx(sp->win); x--; )
  614.                     (void) waddch(sp->win, ' ');
  615.                 }
  616.                 (void) wmove(sp->win, oy, 0);
  617.                 for (x = 0; x < ox; x++)
  618.                 (void) waddch(sp->win, ' ');
  619.                 wattrset(sp->win, attrs);
  620.                 break;
  621.             case 2:
  622.                 (void) wclear(sp->win);
  623.                 break;
  624.             default:
  625.                 break;
  626.         }
  627.         sp->flags &= ~(C_ESC|C_CSI);
  628.         break;
  629.         case 'K':
  630.         switch (sp->parm[0])    {
  631.             case 0:
  632.                 (void) clrtoeol();
  633.                 break;
  634.             case 1:
  635.                 getyx(sp->win, oy, ox);
  636.                 (void) wmove(sp->win, oy, 0);
  637.                 attrs = getattrs(sp->win);
  638.                 wattrset(sp->win, A_NORMAL);
  639.                 for (x = 0; x < ox; x++)
  640.                 (void) waddch(sp->win, ' ');
  641.                 wattrset(sp->win, attrs);
  642.                 break;
  643.             case 2:
  644.                 getyx(sp->win, oy, ox);
  645.                 (void) wmove(sp->win, oy, 0);
  646.                 attrs = getattrs(sp->win);
  647.                 wattrset(sp->win, A_NORMAL);
  648.                 for (x = Getmaxx(sp->win); x--; )
  649.                 (void) waddch(sp->win, ' ');
  650.                 (void) wmove(sp->win, oy, ox);
  651.                 wattrset(sp->win, attrs);
  652.                 break;
  653.             default:
  654.                 break;
  655.         }
  656.         sp->flags &= ~(C_ESC|C_CSI);
  657.         break;
  658.         case 'm':
  659.         sp->flags &= ~(C_ESC|C_CSI);
  660.         if (!sp->nparm)    {
  661.             (void) wattroff(sp->win, A_BOLD|A_DIM|A_UNDERLINE|A_BLINK|A_REVERSE);
  662.             break;
  663.         }
  664.         for (x = 0; x < sp->nparm; x++)    {
  665.             switch (sp->parm[x])    {
  666.                 case 0:
  667.                 (void) wattroff(sp->win, A_BOLD|A_DIM|A_UNDERLINE|A_BLINK|A_REVERSE);
  668.                 break;
  669.                 case 1:
  670.                 (void) wattron(sp->win, A_BOLD);
  671.                 break;
  672.                 case 2:
  673.                 (void) wattron(sp->win, A_DIM);
  674.                 break;
  675.                 case 4:
  676.                 (void) wattron(sp->win, A_UNDERLINE);
  677.                 break;
  678.                 case 5:
  679.                 (void) wattron(sp->win, A_BLINK);
  680.                 break;
  681.                 case 7:
  682.                 (void) wattron(sp->win, A_REVERSE);
  683.                 break;
  684.                 case 21:
  685.                 (void) wattroff(sp->win, A_BOLD);
  686.                 break;
  687.                 case 22:
  688.                 (void) wattroff(sp->win, A_DIM);
  689.                 break;
  690.                 case 24:
  691.                 (void) wattroff(sp->win, A_UNDERLINE);
  692.                 break;
  693.                 case 25:
  694.                 (void) wattroff(sp->win, A_BLINK);
  695.                 break;
  696.                 case 27:
  697.                 (void) wattroff(sp->win, A_REVERSE);
  698.                 break;
  699.                 /* ANSI color sequences? */
  700.                 /* not for now; curses colors are too complex */
  701.                 default:
  702.                     break;
  703.             }
  704.         }
  705.         break;
  706.         case 'A':
  707.         getyx(sp->win, y, x);
  708.         if ((y -= (sp->nparm? sp->parm[0]: 1)) < 0)
  709.             y = 0;
  710.         (void) wmove(sp->win, y, x);
  711.         sp->flags &= ~(C_ESC|C_CSI);
  712.         break;
  713.         case 'B':
  714.         getyx(sp->win, y, x);
  715.         if ((y += (sp->nparm? sp->parm[0]: 1)) >= Getmaxy(sp->win))
  716.             y = Getmaxy(sp->win) - 1;
  717.         (void) wmove(sp->win, y, x);
  718.         sp->flags &= ~(C_ESC|C_CSI);
  719.         break;
  720.         case 'C':
  721.         getyx(sp->win, y, x);
  722.         if ((x += (sp->nparm? sp->parm[0]: 1)) >= Getmaxx(sp->win))
  723.             x = Getmaxx(sp->win) - 1;
  724.         (void) wmove(sp->win, y, x);
  725.         sp->flags &= ~(C_ESC|C_CSI);
  726.         break;
  727.         case 'D':
  728.         getyx(sp->win, y, x);
  729.         if ((x -= (sp->nparm? sp->parm[0]: 1)) < 0)
  730.             x = 0;
  731.         (void) wmove(sp->win, y, x);
  732.         sp->flags &= ~(C_ESC|C_CSI);
  733.         break;
  734.         case 'r':
  735.         (void) wsetscrreg(sp->win, (sp->nparm? sp->parm[0] - 1: 0),
  736.                (sp->nparm > 1? sp->parm[1] - 1: Getmaxy(sp->win) - 1));
  737.         sp->flags &= ~(C_ESC|C_CSI);
  738.         break;
  739.         case 's':
  740.         getyx(sp->win, sp->save.y, sp->save.x);
  741.         sp->save.attr = getattrs(sp->win);
  742.         sp->save.tmarg = sp->win->_tmarg;
  743.         sp->save.bmarg = sp->win->_bmarg;
  744.         sp->save.bkgrnd = sp->win->_bkgd; /* should be a macro for this */
  745.         sp->save.valid = 1;
  746.         sp->flags &= ~(C_ESC|C_CSI);
  747.         break;
  748.         case 'u':
  749.         if (sp->save.valid)    {
  750.             (void) wmove(sp->win, sp->save.y, sp->save.x);
  751.             wattrset(sp->win, sp->save.attr);
  752.             wbkgdset(sp->win, sp->save.bkgrnd);
  753.             (void) wsetscrreg(sp->win, sp->save.tmarg, sp->save.bmarg);
  754.             sp->save.valid = 0;
  755.         }
  756.         sp->flags &= ~(C_ESC|C_CSI);
  757.         break;
  758.         case 'L':
  759.         if (!sp->nparm)
  760.             sp->parm[0] = 1;
  761.         while (sp->parm[0]--)
  762.             (void) winsertln(sp->win);
  763.         sp->flags &= ~(C_ESC|C_CSI);
  764.         break;
  765.         case 'M':
  766.         if (!sp->nparm)
  767.             sp->parm[0] = 1;
  768.         while (sp->parm[0]--)
  769.             (void) wdeleteln(sp->win);
  770.         sp->flags &= ~(C_ESC|C_CSI);
  771.         break;
  772.         case '@':
  773.         if (!sp->nparm)
  774.             sp->parm[0] = 1;
  775.         while (sp->parm[0]--)
  776.             (void) winsch(sp->win, ' ');
  777.         sp->flags &= ~(C_ESC|C_CSI);
  778.         break;
  779.         case 'P':
  780.         if (!sp->nparm)
  781.             sp->parm[0] = 1;
  782.         while (sp->parm[0]--)
  783.             (void) wdelch(sp->win);
  784.         sp->flags &= ~(C_ESC|C_CSI);
  785.         break;
  786.         case 'h':
  787.         case 'l':
  788.         for (x = 0; x < sp->nparm; x++)    {
  789.             switch (sp->parm[x])    {
  790.                 case 4:
  791.                 if (c == 'h')
  792.                     sp->flags |= C_INS;
  793.                 else
  794.                     sp->flags &= ~C_INS;
  795.                 break;
  796.                 /* insert mode is all we handle right now */
  797.                 default:
  798.                     break;
  799.             }
  800.         }
  801.         sp->flags &= ~(C_ESC|C_CSI);
  802.         break;
  803.         default:
  804.         sp->flags &= ~(C_ESC|C_CSI);
  805.         break;
  806.     }
  807. }
  808.  
  809.  
  810.  
  811. static void
  812. curses_clreol (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  813. {
  814. #ifdef SCREENSAVER
  815.     sskick();
  816. #endif
  817.     (void) wclrtoeol(((struct curses_data *) dp)->win);
  818. }
  819.  
  820.  
  821.  
  822. static void
  823. curses_rflush (const struct sessmgr_sw *sm OPTIONAL, void *dp OPTIONAL)
  824. {
  825.     /* stub - later we'll update status here */
  826. }
  827.  
  828.  
  829.  
  830. static void *
  831. curses_create (const struct sessmgr_sw *sm OPTIONAL, struct session *sp OPTIONAL)
  832. {
  833. struct curses_data *ssp;
  834.  
  835.     ssp = mallocw(sizeof *ssp);
  836.     ssp->win = newwin(LINES, COLS, 0, 0);
  837.     (void) scrollok(ssp->win, TRUE);
  838.  
  839.     ssp->bg = (char) SYSback;    /* witness help 'em if they're in an xterm */
  840.     ssp->fg = (char) SYSfore;
  841.     (void) wbkgd(ssp->win, COLOR_PAIR(1));
  842.     wattrset(ssp->win, COLOR_PAIR(1));
  843.  
  844.     ssp->flags = 0;
  845.     ssp->save.valid = 0;
  846.     curscreen = ssp;
  847.     return ssp;
  848. }
  849.  
  850.  
  851.  
  852. static void
  853. curses_destroy (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  854. {
  855.     (void) delwin(((struct curses_data *) dp)->win);
  856.     j_free(dp);
  857. }
  858.  
  859.  
  860.  
  861. static void
  862. curses_clrscr (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  863. {
  864. WINDOW *w;
  865. int l;
  866.  
  867. #ifdef SCREENSAVER
  868.     sskick();
  869. #endif
  870.     w = ((struct curses_data *) dp)->win;
  871.  
  872.     /* This CANNOT be a simple 'wclear (w)', as that clears
  873.        the current 'window' AND the rest of the screen. This
  874.        code properly honors the active 'window'.
  875.      */
  876.     for (l = w->_tmarg; l <= w->_bmarg; l++)    {
  877.         (void) wmove(w, l, 0);
  878.         (void) wclrtoeol(w);
  879.     }
  880.  
  881.     (void) wmove(w, w->_tmarg, 0);
  882. }
  883.  
  884.  
  885.  
  886. /*lint -save -e550 */
  887. static int
  888. curses_wherex (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  889. {
  890. int x, y;
  891.  
  892.     getyx(((struct curses_data *) dp)->win, y, x);
  893.     return x + 1;
  894. }
  895.  
  896.  
  897.  
  898. static int
  899. curses_wherey (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  900. {
  901. WINDOW *w;
  902. int x, y;
  903.  
  904.     w = ((struct curses_data *) dp)->win;
  905.     getyx(w, y, x);
  906.     return y - w->_tmarg + 1;
  907. }
  908.  
  909. /*lint -restore */
  910.  
  911.  
  912.  
  913. static void
  914. curses_window (const struct sessmgr_sw *sm OPTIONAL, void *dp, int x1 OPTIONAL,
  915.     int y1, int x2 OPTIONAL, int y2)
  916. {
  917. WINDOW *w;
  918.  
  919.     w = ((struct curses_data *) dp)->win;
  920.     (void) wsetscrreg(w, y1 - 1, y2 - 1);
  921.     /* ttydriv() assumes the cursor is placed in this window somewhere */
  922.     (void) wmove(w, y1 - 1, 0);
  923. }
  924.  
  925.  
  926.  
  927. static void
  928. curses_gotoxy (const struct sessmgr_sw *sm OPTIONAL, void *dp, int x, int y)
  929. {
  930. WINDOW *w;
  931.  
  932.     w = ((struct curses_data *) dp)->win;
  933.     (void) wmove(w, y + w->_tmarg - 1, x - 1);
  934. }
  935.  
  936.  
  937.  
  938. static void
  939. curses_high (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  940. {
  941.     (void) wattron(((struct curses_data *) dp)->win,
  942.         (unsigned)((((struct curses_data *) dp)->flags & C_BOLD)? A_BOLD: A_REVERSE));
  943. }
  944.  
  945. static void
  946. curses_norm (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  947. {
  948.     (void) wattroff(((struct curses_data *) dp)->win,
  949.          (((struct curses_data *) dp)->flags & C_BOLD)? A_BOLD: A_REVERSE);
  950. }
  951.  
  952.  
  953.  
  954. static void
  955. curses_txtattr (const struct sessmgr_sw *sm OPTIONAL, void *dp, int color)
  956. {
  957.     (void) init_pair (1, color & 0x0f, ((unsigned int) color >> 4) & 0x0f);
  958.     wattrset (((struct curses_data *) dp)->win, COLOR_PAIR(1));
  959. }
  960.  
  961.  
  962.  
  963. static void
  964. curses_refresh (const struct sessmgr_sw *sm OPTIONAL, void *dp)
  965. {
  966.     (void) clearok(((struct curses_data *) dp)->win, TRUE);
  967.     (void) wrefresh (((struct curses_data *) dp)->win);
  968. }
  969.  
  970.  
  971.  
  972. static void
  973. curses_bground (const struct sessmgr_sw *sm OPTIONAL, void *dp, int color)
  974. {
  975.     ((struct curses_data *) dp)->bg = (char) color;
  976.     curses_txtattr (sm, dp, ((int) (((unsigned int)color) << 4) | (int)((struct curses_data *) dp)->fg));
  977.     (void) wbkgd (((struct curses_data *) dp)->win, COLOR_PAIR(1));
  978. }
  979.  
  980.  
  981. static void
  982. curses_fground (const struct sessmgr_sw *sm OPTIONAL, void *dp, int color)
  983. {
  984.     ((struct curses_data *) dp)->fg = (char) color;
  985.     curses_txtattr (sm, dp, (int) ((int) (((unsigned int) (int) ((struct curses_data *) dp)->bg) << 4) | color));
  986.     (void) wbkgd (((struct curses_data *) dp)->win, COLOR_PAIR(1));
  987. }
  988.  
  989.  
  990.  
  991. static void
  992. curses_cursor (const struct sessmgr_sw *sm OPTIONAL, void *dp OPTIONAL, int c)
  993. {
  994.     (void) curs_set(c);
  995. }
  996.  
  997.  
  998.  
  999. static int
  1000. kbchar(int ir)
  1001. {
  1002. unsigned char ch;
  1003. int i;
  1004.  
  1005.     if (ir)
  1006.         kalarm(500);
  1007.     do    {
  1008.         if (kwait(&Keyboard) != 0 && ir)
  1009.             return -1;
  1010.     }
  1011.     while ((i = read(0, &ch, 1)) == 0 || (i == -1 && errno == EWOULDBLOCK))
  1012.         ;
  1013.     kalarm(0);
  1014.     if (i < 0)    {
  1015.         tprintf("NOS PANIC: Lost keyboard\n");
  1016.         where_outta_here(1, "kbchar");
  1017.     }
  1018.     return ch;
  1019. }
  1020.  
  1021.  
  1022.  
  1023. /*
  1024.  * This remains incorrect.  The keyboard process must be recreated as part of
  1025.  * the session manager instead of being independent; this process must be
  1026.  * capable of distributing input from several sources, including the real
  1027.  * keyboard and external sessions.
  1028.  */
  1029.  
  1030. static int
  1031. curses_kbread(const struct sessmgr_sw *sm OPTIONAL, void *dp OPTIONAL)
  1032. {
  1033. static int ungets[10];
  1034. struct keytrie *t;
  1035. static int unget = 0;
  1036. int theungetc[10];
  1037. int c, i, u;
  1038.  
  1039.     i = 0;
  1040.     u = 0;
  1041.     if (unget > i)
  1042.         c = ungets[i++];    /*lint !e727 */
  1043.     else
  1044.         c = kbchar(0);
  1045.     theungetc[u++] = c;
  1046.     t = keys;
  1047.     while (t[c].kt_type == KT_TRIE || t[c].kt_type == KT_TVAL)    {
  1048.         t = t[c].kt_trie;
  1049.         if (unget > i)
  1050.             c = ungets[i++];
  1051.         else
  1052.             c = kbchar(1);
  1053.         if (c == -1)
  1054.             break;
  1055.         theungetc[u++] = c;
  1056.     }
  1057.  
  1058.     if (t[c].kt_type == KT_VAL)    {
  1059.         u = 0;
  1060.         c = t[c].kt_val;
  1061.     } else if (t[c].kt_type == KT_TVAL)   {
  1062.         u = 0;
  1063.         c = t[c].kt_tval;
  1064.     }
  1065.  
  1066.     while (i < unget)
  1067.         theungetc[u++] = ungets[i++];
  1068.     if (u)    {
  1069.         c = theungetc[0];
  1070.         for (i = u; i; i--)
  1071.             ungets[i - 1] = theungetc[i];
  1072.         unget = u - 1;
  1073.     }
  1074.     return c;
  1075. }
  1076.  
  1077.  
  1078.  
  1079. struct sessmgr_sw curses_sessmgr =
  1080. {
  1081.     "curses",
  1082.     SM_SPLIT|SM_STDIO,
  1083.     curses_init,
  1084.     (char *(*)(const struct sessmgr_sw *, char *)) 0,
  1085.     curses_create,
  1086.     curses_opts,
  1087.     curses_swap,
  1088.     curses_putch,
  1089.     curses_clreol,
  1090.     curses_clrscr,
  1091.     curses_wherex,
  1092.     curses_wherey,
  1093.     curses_window,
  1094.     curses_gotoxy,
  1095.     curses_high,
  1096.     curses_norm,
  1097.     curses_bground,
  1098.     curses_fground,
  1099.     curses_txtattr,
  1100.     curses_refresh,
  1101.     curses_cursor,
  1102.     curses_kbread,
  1103.     curses_destroy,
  1104.     0,
  1105.     curses_rflush,
  1106.     curses_flush,
  1107.     curses_suspend,
  1108.     curses_resume,
  1109.     curses_end,
  1110.     0
  1111. };
  1112.  
  1113. #endif
  1114.  
  1115. #endif        /* UNIX */
  1116.